package com.googlecode.mailnet.emf.netmodel.simulation;

import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;

import com.googlecode.mailnet.emf.netmodel.LinkModel;
import com.googlecode.mailnet.emf.netmodel.NetworkConfigurationModel;
import com.googlecode.mailnet.emf.netmodel.NodeModel;
import com.googlecode.mailnet.emf.netmodel.impl.NetworkConfigurationModelImpl;
import com.googlecode.mailnet.info.ISimulationInfo;
import com.googlecode.mailnet.math.distribution.DistributionFormatException;
import com.googlecode.mailnet.netmodel.Link;
import com.googlecode.mailnet.netmodel.NetworkConfiguration;
import com.googlecode.mailnet.netmodel.Node;
import com.googlecode.mailnet.simulation.NetworkSimulator;

public class SimulationContext {
	NetworkConfigurationModel model;
	EMF2NetworkConfiguration emf2config;
	NetworkSimulator simulator = null;
	SimulationStatistics statistics;
	
	public void start(NetworkConfigurationModel model) throws InvalidModelException, DistributionFormatException, IllegalStateException {
		if (model == null) return;
		// listeners.clear();
		this.model = model;
		
		// convert EMF configuration model to real input model
		NetworkConfiguration config = null;
		emf2config = new EMF2NetworkConfiguration();
		config = emf2config.init(model);
		if (config == null) return;
		
		// creating the simulator
		simulator = new NetworkSimulator(config, 1);
		
		
		// binding to model part
		NetworkConfigurationModelImpl modelImpl = (NetworkConfigurationModelImpl) model;
		modelImpl.setSimulationContext(this);
		
		statistics = new SimulationStatistics(simulator.getInfo());
		
		notifyListeners();
	}
	
	public void next() {
		try {
			simulator.makeStep();
		} catch (Exception e) {
			System.out.println(e.toString());
		}
		statistics.evaluateStep();
		notifyListeners();
	}
	
	final Set<ISimulationListener> listeners = new LinkedHashSet<ISimulationListener>();
	
	public void addListener(ISimulationListener listener) {
		listeners.add(listener);
	}
	
	public void removeListener(ISimulationListener listener) {
		listeners.remove(listener);
	}
	
	private void notifyListeners() {
		Iterator<ISimulationListener> it = listeners.iterator();
		while (it.hasNext()) {
			it.next().onChanged(this);
		}
	}
	
	public ISimulationInfo getInfo() {
		return simulator.getInfo();
	}
	
	public Node resolveObject(NodeModel nodeModel) {
		return emf2config.emf2nodes.get(nodeModel);
	}
	
	public Link resolveObject(LinkModel linkModel) {
		return emf2config.emf2links.get(linkModel);
	}
	
	public NodeModel resolveModel(Node node) {
		return emf2config.nodes2emf.get(node);
	}
	
	public LinkModel resolveModel(Link link) {
		return emf2config.links2emf.get(link);
	}
	
	public SimulationStatistics getStatistics() {
		return statistics;
	}
}
